#!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author: Sricor
# @Date: 2022-10-25

""" Yiban Class """
import datetime
import json
import logging
import traceback
from typing import TextIO

from yiban.Apis import User
from yiban.Apis import Task
from yiban.Core import BaseReq
from yiban.Core.Exception import AuthException
from yiban.Tools.cookie import cookiejar_to_string_list, string_list_to_simple_cookie


class Yiban(
    User,
    Task,
):
    def __init__(
            self,
            mobile:   str,
            password: str,
            logger: logging.Logger = logging.getLogger(),
            cache_dir: str = "./data/user_cache"
    ):
        """
        易班 Python API service
        :param mobile:   (必须) 用户账号
        :param password: (必须) 用户密码
        """
        super().__init__(mobile=mobile, password=password)  # init User
        super(User, self).__init__(mobile=mobile, password=password)  # init Task
        # try:
        #     super(User, self).__init__(mobile=mobile, password=password)  # init Task
        # except:
        #     pass
        self.log = UserLogger(logger, self)
        self._cache_dir = cache_dir
        self._update_user_cache = False
        self._logged_in_from_cache = False
        self._data = {}

    async def __aenter__(self):
        # 尝试从文件加载用户登录态
        try:
            # TODO(改为异步)
            with open(f'{self._cache_dir}/{self._mobile}.json', 'r', encoding='utf-8') as f:
                data: dict = json.load(f)
                data["login_time"] = datetime.datetime.fromisoformat(data["login_time"])
            self._data = data
            await self.login(data["user_info"], data["access_token"])
            await self.init_task(
                await self.get_user_access_token(),
                BaseReq(string_list_to_simple_cookie(data['cookies']))
            )
            try:
                raise AuthException("跳过验证校本化Cookie，直接认为其无效")
                await self.task_feedback.get_sign_task()
            except AuthException:
                await self.close_task_req() # 关闭失效的Req
                self.log.logger.info(f'{self._mobile} 校本化Cookie已失效，尝试更新')
                try:
                    await self.init_task(await self.get_user_access_token())
                except AuthException:
                    # 关闭失效的Req的代码在SchoolBasedAuth的auth内部
                    self.log.logger.info(f'{self._mobile} 易班登录态已失效，重新登录')
                    self._update_user_cache = True
                    raise
            self._logged_in_from_cache = True
            self.log.logger.info(f'{self._mobile} 成功从缓存登录')
            self._update_user_cache = False
        except Exception as e:
            self.log.logger.info(f'用户登录态缓存加载失败: {e}')
            self.log.logger.info(f'{self._mobile} 正在通过密码登录')
            await self.login()
            await self.init_task(await self.get_user_access_token())
            self._logged_in_from_cache = False
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        # if self._update_user_cache:
        if True:
            # 保存登录态
            data = {
                "user_info": self.user,
                "access_token": await self.get_user_access_token(),
                "cookies": cookiejar_to_string_list(self.req.session.cookie_jar),
            }
            if self._logged_in_from_cache:
                data["login_time"] = str(self._data["login_time"])
            else:
                data["login_time"] = str(datetime.datetime.now())
            # TODO(改为异步)
            with open(f'{self._cache_dir}/{self._mobile}.json', 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=4)
        await self.close_task_req()


    def get_login_time(self) -> datetime.datetime:
        return self._data["login_time"]


class UserLogger:
    def __init__(self, logger: logging.Logger, yb: Yiban):
        self.logger = logger
        self.yb = yb

    def debug(self, msg: str):
        self.logger.debug(f"{self.yb.get_user_name()}({self.yb.get_user_phone()}) {msg}")

    def info(self, msg: str):
        self.logger.info(f"{self.yb.get_user_name()}({self.yb.get_user_phone()}) {msg}")

    def warning(self, msg: str):
        self.logger.warning(f"{self.yb.get_user_name()}({self.yb.get_user_phone()}) {msg}")

    def error(self, msg: str):
        self.logger.error(f"{self.yb.get_user_name()}({self.yb.get_user_phone()}) {msg}")